package com.dc.bobaoge.project.base.core.mq.config;

import com.own.constant.ConstantCommon;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Correlation;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.config.ContainerCustomizer;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitOperations;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitTemplateConfigurer;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.context.annotation.Bean;

import java.util.UUID;

/**
 * CustomRabbitTemplateConfig
 *
 * @author chenxueli
 * @date 2023-12-13 11:57:00
 */
@SpringBootConfiguration
public class CustomRabbitTemplateConfig {

    @Bean
    @ConditionalOnSingleCandidate(ConnectionFactory.class)
    @ConditionalOnMissingBean({RabbitOperations.class})
    public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory factory) {
        var template = new RabbitTemplate();
        configurer.configure(template, factory);
        // 设置制定一的发送前信息
        template.setBeforePublishPostProcessors(new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                // 这个方法没调用，调用的是下面那个方法
                return message;
            }

            @Override
            public Message postProcessMessage(Message message, Correlation correlation, String exchange, String routingKey) {
                var traceId = MDC.get(ConstantCommon.TRACE_ID);
                if (StringUtils.isBlank(traceId)) {
                    traceId = UUID.randomUUID().toString();
                }
                message.getMessageProperties().setHeader(ConstantCommon.TRACE_ID, traceId);
                return message;
            }
        });
        return template;
    }

    @Bean(name = {"rabbitListenerContainerFactory"})
    @ConditionalOnProperty(prefix = "spring.rabbitmq.listener", name = {"type"}, havingValue = "simple", matchIfMissing = true)
    @SuppressWarnings("all")
    public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(
            SimpleRabbitListenerContainerFactoryConfigurer configurer,
            ConnectionFactory connectionFactory,
            ObjectProvider<ContainerCustomizer<SimpleMessageListenerContainer>> simpleContainerCustomizer
    ) {
        var factory = new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        simpleContainerCustomizer.ifUnique(factory::setContainerCustomizer);
        // 设置接收前的信息
        factory.setAfterReceivePostProcessors(message -> {
            var traceId = message.getMessageProperties().getHeader(ConstantCommon.TRACE_ID);
            if (traceId != null) {
                MDC.put(ConstantCommon.TRACE_ID, traceId.toString());
            } else {
                MDC.put(ConstantCommon.TRACE_ID, UUID.randomUUID().toString());
            }
            return message;
        });
        return factory;
    }

}
